#include <iostream>
#include <thread>
#include <vector>
#include <cmath>
#include <glm/glm.hpp>

#include <ame.h>
#include <render/output/shader.h>

using namespace std;

Object monkey;
Object stuff;
threadControl coreCtrl;
Application application;
Asound* sound = nullptr;
Window* window = nullptr;
OGLRender* render = nullptr;
Shader* shader = nullptr;
Camera* camera = nullptr;
Texture* brickTexture = nullptr;
Texture* rgLogoTexture = nullptr;
Text* text = nullptr;

bool wasd [4];

unsigned int fps = 0;


void calcFPS ( ) {
    while ( application.running ) {
        application.time.wait ( 1000 );
        cout << "FPS:\t" << fps << endl;
        fps = 0;
    }
}

void playAudio ( ) {
    sound -> play ();
}

void mousePositionUpdate () {

    camera -> setCameraTarget ( &application.input.mouse );
}

void keyboardKeyUpdate () {

    char lastKey = application.input.keyboard.key;
    Action lastAction = application.input.keyboard.action;


    if ( lastKey == 'W' && lastAction != UNPRESSED ) {

        wasd [0] = true;

    } else if ( lastKey == 'W' && lastAction == UNPRESSED ) {

        wasd [0] = false;
    }


    if ( lastKey == 'A' && lastAction != UNPRESSED ) {

        wasd [1] = true;

    } else if ( lastKey == 'A' && lastAction == UNPRESSED ) {

        wasd [1] = false;

    }


    if ( lastKey == 'S' && lastAction != UNPRESSED ) {

        wasd [2] = true;

    } else if ( lastKey == 'S' && lastAction == UNPRESSED ) {

        wasd [2] = false;
    }


    if ( lastKey == 'D' && lastAction != UNPRESSED ) {

        wasd [3] = true;

    } else if ( lastKey == 'D' && lastAction == UNPRESSED ) {

        wasd [3] = false;
    }



    if ( wasd [0] ) {

        camera -> setPosition ( glm::vec3 ( camera -> getPosition ().x,
                                            camera -> getPosition ().y,
                                            camera -> getPosition ().z + 0.2) );
    }
    if ( wasd [1] ) {

        camera -> setPosition ( glm::vec3 ( camera -> getPosition ().x + 0.2,
                                            camera -> getPosition ().y,
                                            camera -> getPosition().z ) );
    }
    if ( wasd [2] ) {

        camera -> setPosition ( glm::vec3 ( camera -> getPosition ().x,
                                            camera -> getPosition ().y,
                                            camera -> getPosition().z - 0.2 ) );
    }
    if ( wasd [3] ) {

        camera -> setPosition ( glm::vec3 ( camera -> getPosition ().x - 0.2,
                                            camera -> getPosition ().y,
                                            camera -> getPosition().z ) );
    }



    if ( application.input.keyboard.key == 'E' && application.input.keyboard.action != UNPRESSED ) {

        camera -> setPosition ( glm::vec3 ( camera -> getPosition ().x,
                                            camera -> getPosition ().y + 0.2,
                                            camera -> getPosition().z ) );

    }
    if ( application.input.keyboard.key == 'Q' && application.input.keyboard.action != UNPRESSED ) {

        camera -> setPosition ( glm::vec3 ( camera -> getPosition ().x,
                                            camera -> getPosition ().y - 0.2,
                                            camera -> getPosition().z ) );

    }

    if ( application.input.keyboard.key == 'L' ) {

        shader = new Shader ( "./res/basicShader" );
    }

    if ( application.input.keyboard.key == GLFW_KEY_ESCAPE ) {
        application.running = false;
    }
}

void Update ( ) {

    camera -> applyChanges ();

//    camera -> setFieldOfView ( ( application.input.mouse.posY + application.settings.windowHeight ) / 100);

    shader -> Bind ();
    brickTexture -> Bind ();
    shader -> Update ( monkey.transform, *camera );
    shader -> Update ( stuff.transform, *camera );
    
    monkey.transform.rotate ( glm::vec3 ( 0.0,
                                                 0.1,
                                                 0.0 ) );
    
    monkey.mesh -> Draw ();

    rgLogoTexture -> Bind();

    stuff.mesh -> Draw ();


    //text->Print();

    
    fps++;
}

int main ( )
{
    application.appName = "AMEP";
    application.companyName = "assblast";
    application.update = Update;
    application.mousePositionCallback = mousePositionUpdate;
    application.keyboardCallback = keyboardKeyUpdate;
    application.openGLTools.OpenGLContext = OGLC_GLFW;
    
    application.settings.fullscreen = false;
    application.settings.windowName = "AREP";
    application.settings.windowWidth = 960;
    application.settings.windowHeight = 540;
    application.settings.windowMonitor = 0;
    application.settings.windowResizeble = false;
    application.settings.MSAA = 8;

    application.input.mouse.sensitivity = 0.05;
    
    window = new Window ( &application );
    render = new OGLRender ( &application, window );
    shader = new Shader ( "./res/basicShader" );
    
    camera = new Camera ( glm::vec3 ( 0.0, 0.0, -5.0 ), 70.0, 
                          18/9,
                          0.01, 100.0
                        );

    brickTexture = new Texture ( "./bricks.jpg", ATexFilter_Linear );
    rgLogoTexture = new Texture ( "./RGLogo.jpg", ATexFilter_Linear );

    window -> grabCursor ( true );
    
    Listener listener;
    Source source;
    
    listener.attributes.position [0] = 0.0;
    listener.attributes.position [1] = 0.0;
    listener.attributes.position [2] = 1.0;
    
    listener.attributes.velocity [0] = 0.0;
    listener.attributes.velocity [1] = 0.0;
    listener.attributes.velocity [2] = 0.0;
    
    listener.attributes.orientation [0] = 0.0;
    listener.attributes.orientation [1] = 0.0;
    listener.attributes.orientation [2] = 1.0;
    
    listener.attributes.orientation [3] = 0.0;
    listener.attributes.orientation [4] = 1.0;
    listener.attributes.orientation [5] = 0.0;
    
    source.attributes.position [0] = 0.0;
    source.attributes.position [1] = 0.0;
    source.attributes.position [2] = 0.0;
    
    source.attributes.velocity [0] = 0.0;
    source.attributes.velocity [1] = 0.0;
    source.attributes.velocity [2] = 0.0;
    
    sound = new Asound ( "sound.wav", source, listener );

    string txt = "QWERTYU";
    /*text = new Text ( txt, 2.0f, glm::vec2 ( 25.0f, 25.0f ), glm::vec3 ( 0.5, 0.8f, 0.2f ), 
                      application.settings.windowWidth, application.settings.windowHeight );*/
                              
    monkey.mesh = new Mesh ( "./monkey.obj" );
    stuff.mesh = new Mesh ( "./stuff.obj" );

    coreCtrl.threads.resize ( 1 );
    coreCtrl.threads [0] = new std::thread ( calcFPS );
    coreCtrl.threads [1] = new std::thread ( playAudio );
    
    render -> joinToMainCycle ();

    coreCtrl.threads [0] -> detach ();

    return 0;
}
